package com.lcy.struct.bTreePlus.disk.core.execute;

import com.lcy.struct.bTreePlus.disk.core.BPlusTreeFactory;
import com.lcy.struct.bTreePlus.disk.enums.BplusTreeEnums;
import com.lcy.struct.bTreePlus.disk.index.BTreeIndex;
import com.lcy.struct.bTreePlus.disk.item.TreeNode;
import com.lcy.struct.bTreePlus.disk.recovery.transation.TransactionCenter;
import com.lcy.struct.bTreePlus.entity.TransactionJoinInfo;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * @author lucongyang
 * @date Created in  9:57
 * @description 面向外部
 */
public class BPlusTreeExecution {
    /**
     * 新增数据操作
     */
    public void save(Object data, Comparable... id) {
        TreeNode treeNode = new TreeNode();
        BTreeIndex bTreeIndex = new BTreeIndex();
        Arrays.stream(id).forEach(bTreeIndex::addIndex);
        treeNode.setIndex(bTreeIndex);
        treeNode.setData(data);
        List<TreeNode> list = new ArrayList<>();
        list.add(treeNode);
        // 写undo
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
            transactionJoinInfo.setIndex(treeNode.getIndex());
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            transactionJoinInfoList.add(transactionJoinInfo);
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.ADD);
        }
        // 操作
        BPlusTreeFactory.batchAdd(list, true);
    }

    /**
     * 新增数据操作
     */
    public void saveBatch(List<TreeNode> list) {
        // 写undo
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            for (TreeNode treeNode : list) {
                TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
                transactionJoinInfo.setIndex(treeNode.getIndex());
                transactionJoinInfoList.add(transactionJoinInfo);
            }
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.ADD);
        }
        // 操作
        BPlusTreeFactory.batchAdd(list, true);
    }

    /**
     * 修改数据操作
     * 不修改主键
     */
    public void update(Object data, Comparable... id) {
        TreeNode treeNode = new TreeNode();
        BTreeIndex bTreeIndex = new BTreeIndex();
        Arrays.stream(id).forEach(bTreeIndex::addIndex);
        treeNode.setIndex(bTreeIndex);
        treeNode.setData(data);
        // 写undo
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
            transactionJoinInfo.setIndex(bTreeIndex);
            transactionJoinInfo.setTreeNode(treeNode);
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            transactionJoinInfoList.add(transactionJoinInfo);
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.UPDATE);
        }
        // 操作
        BPlusTreeFactory.update(bTreeIndex, treeNode);
    }

    /**
     * 批量修改数据操作
     */
    public void updateBatchById(List<TreeNode> list) {
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            for (TreeNode treeNode : list) {
                // 写undo
                TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
                transactionJoinInfo.setIndex(treeNode.getIndex());
                transactionJoinInfo.setTreeNode(treeNode);
                transactionJoinInfoList.add(transactionJoinInfo);
            }
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.UPDATE);
        }
        // 操作
        BPlusTreeFactory.batchUpdateById(list);
    }

    /**
     * 删除数据操作
     */
    public void remove(Comparable... id) {
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            // 写undo
            BTreeIndex index = new BTreeIndex();
            Arrays.stream(id).forEach(index::addIndex);
            TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
            transactionJoinInfo.setIndex(index);
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            transactionJoinInfoList.add(transactionJoinInfo);
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.DEL);
        }
        // 操作
        List<Comparable[]> list = new ArrayList<>();
        list.add(id);
        BPlusTreeFactory.batchDel(list);
    }

    /**
     * 删除数据操作
     */
    public void removeByIds(List<Comparable> ids) {
        Comparable[] idArr = new Comparable[ids.size()];
        ids.toArray(idArr);
        if (TransactionCenter.getInstance().isWithinTransaction()) {
            List<TransactionJoinInfo> transactionJoinInfoList = new ArrayList<>();
            for (Comparable index : ids) {
                BTreeIndex bTreeIndex = new BTreeIndex();
                bTreeIndex.addIndex(index);
                // 写undo
                TransactionJoinInfo transactionJoinInfo = new TransactionJoinInfo();
                transactionJoinInfo.setIndex(bTreeIndex);
                transactionJoinInfoList.add(transactionJoinInfo);
            }
            TransactionCenter.getInstance().join(transactionJoinInfoList, BplusTreeEnums.TransactionType.DEL);
        }
        // 操作
        List<Comparable[]> list = new ArrayList<>();
        ids.forEach(e -> list.add(new Comparable[]{e}));
        BPlusTreeFactory.batchDel(list);
    }

    /**
     * 查询
     */
    public Object selectById(Comparable... id) {
        return BPlusTreeFactory.findDataOnDisk(id);
    }

    public static BPlusTreeExecution getInstance() {
        return Singleton.INSTANCE;
    }

    private static class Singleton {
        private static final BPlusTreeExecution INSTANCE = new BPlusTreeExecution();
    }

    private BPlusTreeExecution() {
    }
}
